-module(event_manager).
-include_lib("event_model.hrl").

-export([init/4]).

init(Main, Routers, Generator, FileSuf)->
  run(Routers, Generator,minheap:new(),[],[], FileSuf),
  Main ! finish.

run(Routers, Generator, EventList, Finish, Lost, FileSuf) ->
  run(Routers, Generator, EventList, Finish, Lost, 0, FileSuf).

run(Routers, Generator, EventList, Finish, Lost, EventAPSize, FileSuf) ->
  ListSize = minheap:heapSize(EventList),
  if
    ListSize>0->
      %io:format("~p~n",[EventList]),
      { {item, _, He}, Te } = minheap:extract(EventList),
      %io:format("~p~n",[He]),
      #event{type=Type, packet=Packet} = He,
      case Type of
        arrive ->
          {NewEL, NewFinish, NewLost, IsArrive} = arrive_work(Packet, Routers, Generator, Te, Finish, Lost, EventAPSize);
        departure ->
          IsArrive = false,
          {NewEL, NewFinish, NewLost} = departure_work(Packet, Routers, Te, Finish, Lost)
      end;
    true ->
      Generator ! {self(), {one}},
      receive
        {Generator, {have, EL}} ->
          NewEL = insert_heap(EL, EventList);
        {Generator, {empty}} ->
          edm_utils:display_result(lists:reverse(Finish), lists:reverse(Lost), FileSuf),
          NewEL = empty
      end,
      IsArrive = false,
      NewFinish = Finish,
      NewLost = Lost
  end,
  case NewEL of
    empty ->
      empty;
    _ ->
      if
        IsArrive ->
          run(Routers, Generator, NewEL, NewFinish, NewLost, EventAPSize+1, FileSuf);
        true ->
          run(Routers, Generator, NewEL, NewFinish, NewLost, EventAPSize, FileSuf)
      end
  end.

arrive_work(Packet, Routers, Generator, Te, Finish, Lost, EventAPSize) ->
  Routers ! {self(), {arrive, Packet}},
  receive
    {Routers, {finish, NewPacket}} ->
      NewFinish = [NewPacket|Finish],
      NewLost = Lost,
      NewEL = Te,
      IsArrive = false;
    {Routers, {ok, NewPacket, WaitTime, CompleteTime}} ->
      NewEvent = #event{type=departure, packet=NewPacket},
      NewFinish = Finish,
      NewLost = Lost,
      Generator ! {self(),{range,{WaitTime, CompleteTime}}},
      receive
        {Generator, {have, EL}}->
          NewGEL = insert_heap(EL, Te);
        {Generator, {empty}}->
          NewGEL = Te
      end,
      IsArrive = true,
      NewEL = insert_heap([NewEvent], NewGEL);
    {Routers, {loss, NewPacket}} ->
      NewFinish = Finish,
      NewLost = [NewPacket#packet{event_number=EventAPSize}|Lost],
      NewEL = Te,
      IsArrive = true
  end,
  {NewEL, NewFinish, NewLost, IsArrive}.

departure_work(Packet, Routers, Te, Finish, Lost) ->
  Routers ! {self(), {leave, Packet}},
  receive
    {Routers, {leaved, NewPacket}} ->
      NewEL = insert_heap([#event{packet=NewPacket}], Te)
  end,
  {NewEL, Finish, Lost}.

insert_heap([], Heap) ->
  Heap;

insert_heap([H|T], Heap) ->
  #event{type=Type, packet=NewPacket}=H,
  #packet{timestamps=Timestamps} = NewPacket,
  [HT|_] = Timestamps,
  #timestamp{atime=ATime, ctime=CTime} = HT,
  case Type of
    arrive ->
      Par = ATime;
    departure ->
      Par = CTime
  end,
  NewHeap = minheap:insert(Par, H, Heap),
  insert_heap(T, NewHeap).
